package com.bsoft.gol.hcs.specialist.service.impl;

import ctd.controller.exception.ControllerException;
import ctd.persistence.DAOFactory;
import ctd.util.AppContextHolder;
import ctd.util.JSONUtils;
import com.bsoft.gol.hcs.enumcase.FactorFlagEnum;
import com.bsoft.gol.hcs.enumcase.VisitRecordEnum;
import lombok.extern.slf4j.Slf4j;
import org.atag.core.exception.ServiceException;
import org.springframework.util.CollectionUtils;
import com.bsoft.gol.hcs.satisfaction.dao.SatisfactionProduceRecordDAO;
import com.bsoft.gol.hcs.satisfaction.entity.SatisfactionProduceRecord;
import com.bsoft.gol.hcs.specialist.bean.ProduceFusStatement;
import com.bsoft.gol.hcs.specialist.bean.response.FactorData;
import com.bsoft.gol.hcs.specialist.dao.FollowUpRouteDetailFactorDAO;
import com.bsoft.gol.hcs.specialist.entity.FollowUpRoute;
import com.bsoft.gol.hcs.specialist.entity.FollowUpRouteDetail;
import com.bsoft.gol.hcs.specialist.entity.FollowUpRouteDetailFactor;
import com.bsoft.gol.hcs.specialist.service.IFollowUpCommonService;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 抽象的随访计划生成类
 *
 * @author neoLin - 2022/06/06 16:55
 **/
@Slf4j
public abstract class AbstractProducePlanService {


    /**
     * 生成计划
     */
    public abstract void producePlan();

    public abstract void produce(FollowUpRoute followUpRoute, String operatorId);

    /**
     * 处理门诊就诊记录 {@link VisitRecordEnum#OUTPATIENT_VISIT_RECORD}
     */
    public abstract void handleForOutpatient(ProduceFusStatement statement, String patientId, String departmentId);

    /**
     * 处理住院就诊记录 {@link VisitRecordEnum#INPATIENT_VISIT_RECORD}
     */
    public abstract void handleForInpatient(ProduceFusStatement statement, String patientId, String departmentId);


    /**
     * 处理检验记录 {@link VisitRecordEnum#INSPECTION_RECORD}
     */
    public abstract void handleForInspectionForm(ProduceFusStatement statement, String patientId, String departmentId);
    /**
     * 处理检查记录 {@link VisitRecordEnum#CHECK_RECORD}
     */
    public abstract void handleForCheckForm(ProduceFusStatement statement, String patientId, String departmentId);
    /**
     * 处理治疗记录 {@link VisitRecordEnum#TREATMENT_RECORD}
     */
    public abstract void handleForTreatmentForm(ProduceFusStatement statement, String patientId, String departmentId);

    /**
     * 处理发药记录 {@link VisitRecordEnum#DISPENSING_RECORD}
     */
    public abstract void handleForDispensing(ProduceFusStatement statement, String patientId, String departmentId);

    /**
     * 处理手术记录 {@link VisitRecordEnum#SURGICAL_RECORD}
     */
    public abstract void handleForSurgical(ProduceFusStatement statement, String patientId, String departmentId);


    /**
     * 处理随访路径详情
     */
    protected List<String> handleFollowUpRouteDetail(ProduceFusStatement statement) {
        log.info("---statement-->"+ JSONUtils.writeValueAsString(statement) );
        FollowUpRouteDetail followUpRouteDetail = statement.getFollowUpRouteDetail();
        FollowUpRoute followUpRoute = statement.getFollowUpRoute();
        //随访路径详情id
        Long routeDetailId = followUpRouteDetail.getRouteDetailId();
        //循环执行机制 0 不执行 1 执行
        Byte isLoopExecute = followUpRouteDetail.getIsLoopExecute();
        //查询随访路径详情因素
        //factorFlag因素类型
        FollowUpRouteDetailFactorDAO followUpRouteDetailFactorDAO = DAOFactory.getDAO(FollowUpRouteDetailFactorDAO.class);
        List<FollowUpRouteDetailFactor> followUpRouteDetailFactors =
                followUpRouteDetailFactorDAO.queryByRouteDetailId(routeDetailId, FactorFlagEnum.START.getType());
        log.info("---followUpRouteDetailFactors-->"+ JSONUtils.writeValueAsString(followUpRouteDetailFactors) );
        List<String> previousList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(followUpRouteDetailFactors)) {
            //遍历的所有因素依次执行筛选:
            //and相连的因素检索出来的数据求交集，遇到OR连接符时，把前面检索出来的数据集合保存，
            //后面检索出来的数据在遇到下一个OR连接符或者结束时与前面检索出来的数据集合求并集

            //病人因素信息存储集合，key是病人id，value是按顺序存储的因素数据集合
            Map<String, List<FactorData>> patientInfoMap = new HashMap<>(256);
            //处理因素列表得到人员信息集合和因素数据集合
            IFollowUpCommonService followUpCommonService = AppContextHolder.get().getBean(IFollowUpCommonService.class);
            try {
                followUpCommonService.handleFactorList(followUpRoute, isLoopExecute, followUpRouteDetailFactors,
                        previousList, patientInfoMap);
                
                statement.setPatientInfoMap(patientInfoMap);
            } catch (ControllerException e) {
                throw new ServiceException(e.getMessage());
            }
            log.info("---previousList-->"+ JSONUtils.writeValueAsString(previousList) );
            //去重
            if (!CollectionUtils.isEmpty(previousList)) {
                previousList = previousList.stream().distinct().collect(Collectors.toList());
                log.info("---previousList.stream()--->"+ JSONUtils.writeValueAsString(previousList) );
            }
            if (CollectionUtils.isEmpty(previousList)) {
                log.info("RouteDetailId:{},子路径没有检索到符合条件的人员数据", routeDetailId);
            } else {
                log.info("RouteDetailId:{},子路径检索到符合条件的人员数据如下:{}", routeDetailId, JSONUtils.toString(previousList));
            }
        }
        return previousList;
    }


    /**
     * 处理随访路径详情时 根据就诊类型 保存的前置处理
     *
     * @param visitType     就诊类型  {@link VisitRecordEnum}
     * @param businessId 就诊记录id 各表主键
     * @param routeDetailId 随访路径详细id
     * @return 是否需要生成计划 true 是  false否
     */
    protected boolean needProduce(VisitRecordEnum visitType, String businessId,
                                  Long routeDetailId) {
        //得到要生成随访计划的就诊类型记录之后，需要判断该子路径有没有给该就诊类型记录生成过。生成过则不用再生成了。
        SatisfactionProduceRecordDAO dao = DAOFactory.getDAO(SatisfactionProduceRecordDAO.class);
        SatisfactionProduceRecord fusAfterPlanProduceRecord =
                dao.getByRouteDetailId(routeDetailId, visitType.getType().toString(), businessId);

        if (Objects.nonNull(fusAfterPlanProduceRecord)) {
            log.info("该子路径给该就诊类型记录生成过随访计划，跳过生成;类型:{},关联主键:{}" +
                            "fusAfterPlanProduceRecord:{}",
                    visitType, businessId, JSONUtils.toString(fusAfterPlanProduceRecord));
            return false;
        }
//        if (CommonUtils.isNotNull(visitRecordId)) {
//            //判断医生站设置
//            FollowUpPathRouteDAO followUpPathRouteDAO = DAOFactory.getDAO(FollowUpPathRouteDAO.class);
//            FollowUpPathRouteEntity followUpPathRoute =
//                    followUpPathRouteDAO.getFuprByCardNoAndSource(organizationId, visitRecordId,
//                            visitType.getType());
//            //随访设置随访类型:0不需要随访、1需要随访
//            if (followUpPathRoute != null &&
//                    (followUpPathRoute.getFollowUpType() == (byte) 0 || routeId.equals(followUpPathRoute.getRouteId()))) {
//                log.info("根据医生站嵌入设置不生成随访计划，跳过生成;类型:{},关联主键:{}" +
//                                "followUpPathRoute:{}",
//                        visitType, visitRecordId, JSONUtils.toString(followUpPathRoute));
//                return false;
//            }
//        }
        return true;
    }

    /**
     * 计算提前通知患者的天数
     */
    protected Integer getAdvanceNotifyDate(FollowUpRouteDetail followUpRouteDetail) {
        Integer advanceNotifyDate = 1;
        //是否通知患者，0不通知，1通知
        if (followUpRouteDetail.getIsNotify() == (byte) 1) {
            IFollowUpCommonService followUpCommonService = AppContextHolder.get().getBean(IFollowUpCommonService.class);
            return followUpCommonService.getAdvanceNotifyDate(null, followUpRouteDetail,
                    followUpRouteDetail.getRouteDetailId(), advanceNotifyDate);
        }
        return advanceNotifyDate;
    }

    /**
     * 保存因素使用记录
     *
     * @param statement 随访上下文
     * @param patientId 患者id
     * @param recordId  随访计划主键
     */
    protected void saveFusFactorDataRecord(ProduceFusStatement statement, String patientId, String recordId) {
        FollowUpRoute followUpRoute = statement.getFollowUpRoute();
        FollowUpRouteDetail followUpRouteDetail = statement.getFollowUpRouteDetail();
        List<FactorData> factorDataList = statement.getPatientInfoMap().get(patientId);
        IFollowUpCommonService followUpCommonService = AppContextHolder.get().getBean(IFollowUpCommonService.class);
        followUpCommonService.saveFusFactorDataRecord(followUpRoute.getFollowType(), followUpRouteDetail.getRouteDetailId(),
                factorDataList, null, recordId);
    }


    /**
     * 获取随访计划时间
     * @param statement  随访上下文
     * @param patientId 患者id
     * @param recordTime 就诊记录时间
     */
    protected Date getStartPlanTime(ProduceFusStatement statement, String patientId, Date recordTime){
        FollowUpRouteDetail followUpRouteDetail = statement.getFollowUpRouteDetail();
        List<FactorData> factorDataList = statement.getPatientInfoMap().get(patientId);
        IFollowUpCommonService followUpCommonService = AppContextHolder.get().getBean(IFollowUpCommonService.class);
        try {
            return followUpCommonService.getStartPlanTime(followUpRouteDetail,
                    factorDataList,
                    statement.getFollowUpRoute().getFollowType(), null
                    , recordTime);
        } catch (ControllerException e) {
            throw new ServiceException(e.getCode(), e.getMessage());
        }
    }
}
